package com.atguigu.com.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.com.seckill.Interceptor.CatInterceptor;
import com.atguigu.com.seckill.feign.CouponFeign;
import com.atguigu.com.seckill.feign.ProductFeign;
import com.atguigu.com.seckill.service.SeckillService;
import com.atguigu.com.seckill.to.SeckillSkuRedisTo;
import com.atguigu.com.seckill.vo.UserInfoVo;
import org.apache.commons.codec.StringEncoderComparator;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
public class SeckillServiceImpl implements SeckillService {

    @Autowired
    CouponFeign couponFeign;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    ProductFeign productFeign;

    @Autowired
    RedissonClient redissonClient;


    public final String SECKILL_SKU = "seckill"; //sku信息
    private final String SECKILL_STOCK = "seckill:stock"; //信号量
    private final String SECKILL_UPLOAD_LOCK = "seckill:upload:lock"; //分布式锁
    private final String SESSIONS_CACHE_PREFIX = "seckill:session";


    /**
     * 获取秒杀商品
     * @return
     */
    @Override
    public List<SeckillSkuRedisTo> getSeckill() {
//        ReentrantLock reentrantLock = new ReentrantLock();
//        reentrantLock.lock();
//        reentrantLock.unlock();
        //获取当前时间
        long time = new Date().getTime();
        //从redis中获取时间戳信息
        Set<String> keys = redisTemplate.keys(SESSIONS_CACHE_PREFIX + "*");
        for (String key : keys) {
            String replace = key.replace(SESSIONS_CACHE_PREFIX, "");
            String[] split = replace.split("_");
            long start = Long.parseLong(split[0]);
            long end = Long.parseLong(split[1]);
            if (start<time&&time<end){
                //从redis中获取这个时间段的商品id信息
                List<String> range = redisTemplate.opsForList().range(key, -100, 100);
                    BoundHashOperations<String, String, Object> hashOps = redisTemplate.boundHashOps(SECKILL_SKU);
                List<Object> objects = hashOps.multiGet(range);//multiGet获取多个key的值
                if (objects!=null){
                    List<SeckillSkuRedisTo> seckillSkuRedisTos = JSON.parseArray(objects.toString(), SeckillSkuRedisTo.class);
                    return seckillSkuRedisTos;
                }
                break;
            }
        }
        return null;
    }

    /**
     * 秒杀
     * @param killId
     * @param code
     * @param num
     * @return
     */
    @Override
    public String kill(String killId, String code, Integer num) {
        //获取用户id
        UserInfoVo userInfoVo = CatInterceptor.threadlocal.get();
        Long memberId = userInfoVo.getId();
        //获取当前秒杀商品的详细信息
        BoundHashOperations<String, String, String> boundHashOps = redisTemplate.boundHashOps(SECKILL_SKU);
         String s = boundHashOps.get(killId);
         if (StringUtils.isEmpty(s)){
             return null;
         }else {
             SeckillSkuRedisTo skuRedisTo = JSON.parseObject(s, SeckillSkuRedisTo.class);
             //获取系统当前时间
             long time = new Date().getTime();
             Long endTime = skuRedisTo.getEndTime();
             Long startTime = skuRedisTo.getStartTime();
             if (time>=startTime&&time<=endTime){
                 //验证随机码
                 String randomCods = skuRedisTo.getRandomCods();
                 if (randomCods.equals(code)){
                     //判断商品数量是否大于最大购买数量
                     if (num<=skuRedisTo.getSeckillLimit()){
                         //防止用户重复购买 场次id+商品id+用户id
                         String userId = memberId.toString()+killId;
                         long end = endTime-startTime;
                         //放入商品数量 同时判断redis中是否含有该数量 如果又则返回false
                         Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(userId, num.toString(), end, TimeUnit.MILLISECONDS);
                         if (aBoolean){
                             //扣减信号量
                             RSemaphore semaphore = redissonClient.getSemaphore(SECKILL_STOCK + randomCods);
                             try {
                                 boolean b = semaphore.tryAcquire(num, 50, TimeUnit.MILLISECONDS);
                                 //快速下单 发送消息
                             } catch (InterruptedException e) {
                                 return null;
                             }
                         }else {
                             return null;
                         }
                     }
                 }else {
                     return null;
                 }
             }else {
                 return null;
             }
             return null;
         }
    }
}
